package conductores;

import java.io.FileWriter;
import java.io.IOException;
//import java.util.Iterator;
//import java.util.List;
//import java.util.Properties;
import java.util.Scanner;
import java.util.concurrent.TimeUnit;

import aima.search.framework.Problem;
import aima.search.framework.Search;
import aima.search.framework.SearchAgent;
import aima.search.framework.SuccessorFunction;
import aima.search.informed.HillClimbingSearch;
import aima.search.informed.SimulatedAnnealingSearch;

public class Main {	
	public static void main(String[] args) throws Exception {

		int steps = 600;
		int dg = 400;
		int K=70;
		double lamb = 0.05f;
		
		int ncond;
		int nuser;
		int algoritmo;
		int estadoI;
		Scanner scanner = new Scanner(System.in);
		System.out.println("Introduzca el numero de usuarios");
		nuser = scanner.nextInt();
		
		System.out.println("Introduzca el numero de conductores");
		ncond = scanner.nextInt();
		
		System.out.println("Escoja el tipo de algoritmo:"); 
		System.out.println("1. Hill Climbing");
		System.out.println("2. Simulated Annealing");
		algoritmo = scanner.nextInt();
		
		if(algoritmo==2){
			System.out.println("Defina el numero de pasos");
			steps = scanner.nextInt();
			System.out.println("Defina el parametro K");
			K = scanner.nextInt();
			System.out.println("Defina el parametro lamb*1000");
			lamb = (double)scanner.nextInt()/1000;
			System.out.println("lamb="+lamb);
			System.out.println("Defina el parametro dg");
			dg = scanner.nextInt();
			
		}
		
		
		System.out.println("Introduzca el tipo de estado inicial");
		estadoI = scanner.nextInt();
		
		// Inicializamos el contexto
		Context.getInstance().setNombreUsuaris(nuser);
		Context.getInstance().setNumConductores(ncond);
		Context.getInstance().init();
		IEstadoInicial estadoInicial;
		Board board;
		switch(estadoI){
		case 1:estadoInicial = new EstadoInicial1();break;
		case 2:estadoInicial = new EstadoInicial2();break;
		case 3:estadoInicial = new EstadoInicial3();break;
		default:estadoInicial = new EstadoInicial3();break;
		}

		board=new Board(estadoInicial);
		Context.getInstance().addOperacion(new OpMove());
		Context.getInstance().addOperacion(new OpSwap());
		Context.getInstance().addOperacion(new OpDeleteConductor());		
		System.out.println("Lista de Operadores: OPMove,OpSwap,OPDeleteConductor");
		
		printState(board, false, "start.csv", 0, null);		
		
		SuccessorFunction successorFunction = new SucesorConductores();
		Search search;
		switch(algoritmo) {
        case 1:
            search = new HillClimbingSearch();
            successorFunction = new SucesorConductores();
            break;
        case 2:
            search = new SimulatedAnnealingSearch(steps, dg, K, lamb);
            successorFunction = new SucesorConductoresSA();
            break;
        default:
            search = new HillClimbingSearch();
            successorFunction = new SucesorConductores();
            break;
        }
		 		
		Problem problem = new Problem(board, successorFunction,
		new ConductoresGoalTest(), new FuncionDeBondad(board));
		long startTime = System.currentTimeMillis();
		SearchAgent agent = new SearchAgent(problem, search);
		long endTime = System.currentTimeMillis();
		
		//printActions(agent.getActions());		
		//printInstrumentation(agent.getInstrumentation());
		printState((Board)search.getGoalState(), false, "end.csv", endTime - startTime, agent);
		
	
	}
	
	private static void printState(Board board, boolean context, String nom, long time, SearchAgent agent) {
		
		try
		{
		    FileWriter writer = new FileWriter(nom);
		    if(context) {
		    	writer.append(Context.getInstance().toCSV());
		    }
		    //writer.append(board.toCSV());
		    
//		    String stime = String.format("%d min, %d sec", 
//		    	    TimeUnit.MILLISECONDS.toMinutes(time),
//		    	    TimeUnit.MILLISECONDS.toSeconds(time) - 
//		    	    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(time))
//		    	);
		    
		    String stime = String.format("%d s", TimeUnit.MILLISECONDS.toSeconds(time));
		    
		    System.out.println(Context.SEPARATOR+"End en "+stime+"segundos"+"\n");
		    writer.append("\n"+"\n");
		    writer.append(Context.SEPARATOR+"Nº conductores:"+Context.SEPARATOR+board.conductores.size()+"\n");
		    writer.append(Context.SEPARATOR+"Tiempo:"+Context.SEPARATOR+stime+"\n");
		    writer.append(Context.SEPARATOR+"Distancia:"+Context.SEPARATOR+board.getDistanciaTotal()+"\n");
		    if(agent!=null){writer.append(Context.SEPARATOR+"Numero de nodos:"+Context.SEPARATOR+agent.getInstrumentation());}
		    writer.flush();
		    writer.close();
		}
		catch(IOException e)
		{
		     e.printStackTrace();
		} 
	}
	/*
	private static void printActions(List<String> list) {
		System.out.println("<ActionList>\n");
		for (int i = 0; i < list.size(); i++) {
			String action = list.get(i);
			System.out.println("<Action" + i + ">" + action + "</Action" + i
					+ ">\n");
		}
		System.out.println("</ActionList>");
		

	}
	
	private static void printInstrumentation(Properties properties) {
        String key = null;
        String property = null;
		Iterator keys = properties.keySet().iterator();
        
		while (keys.hasNext()) {
            key = (String) keys.next();
            property = properties.getProperty(key);
            System.out.println(key + " : " + property);
        }
        
    }
*/
}